#!/usr/bin/env python
# -*- coding: utf-8 -*-

from ..mqtt import mqtt
import time
import json

import random

import logging
logging.basicConfig(level=logging.DEBUG)

class MqttRouterProxy(object):

    def __init__(self, uuid, mqtt_host):
        self._data = {}
        self.uuid = uuid
        self._data['id'] = uuid

        config = {
            'client_id': uuid,
            'host': mqtt_host,
            'userdata': {},
        }

        self.controller = mqtt.create_interface(config)
        self.message_callback_add()
        self.subscribe()



    def message_callback_add(self):
        topic = '/'.join(['down', self.uuid , '#'])
        self.controller.client.message_callback_add(topic, self.on_message)

    def subscribe(self):
        topic = 'down/' + self.uuid + '/#'
        self.controller.push_task('subscribe', topic)


    def publish(self, *args, **kwargs):
        print('publish', args, kwargs)
        topic = '/'.join(['up', self.uuid ] + list(args))
        self.controller.push_task( 'publish', topic, kwargs)


    def on_message(self, client, userdata, msg):
        print(' my default, on_message, userdata,', userdata)
        print("Message: " + msg.topic + " " + str(msg.payload))

        args = msg.topic.split('/')[1:]
        
        kwargs = msg.payload.decode()
        kwargs = json.loads(kwargs)
        print("Message: args, kwargs, " , args, kwargs)
        self.on_message_call(*args, **kwargs)

    def on_message_call(self, code, method, *args, userdata=None, **kwargs):
        print("on_message_call, code, method, userdata, args, kwargs" , 
            code, method, userdata, args, kwargs)

        model, code = args and args[0:2] or ['router', code ]
        call_args = args and args[2:] or ()
        
        obj = env[model]
        result = getattr(obj, 'on_message_' + method)(code, *call_args, **kwargs)
        print("Message 3, result: ", result)
        ack_args = [method] + list(args)
        self.publish( 'ack', *ack_args, userdata=userdata, result=result )


        # self.print_menu()


class BaseModel(object):
    _records = {}

    def __init__(self, code):
        rec = self._records.get(code)
        if not rec:
            self._records[code] = {
                'code': code
            }
        
        self._data = self._records.get(code)

    def unlink(self):
        code = self._data['code']
        rec = self._records.get(code)
        if rec:
            del self._records[code]
            return True

        return False

    def read(self):
        return self._data 


    @classmethod
    def search_by_code(cls, code):
        return cls(code)

    @classmethod
    def on_message_put(cls, code, values=None, *args, **kwargs):
        self = cls.search_by_code(code)
        print('on_message_put, ', cls.__name__,  self._data, values  )
        self._data.update(values )
        print('on_message_put, ', self._data )
        return True

    @classmethod
    def on_message_get(cls, code, *args, **kwargs):
        self = cls.search_by_code(code)
        print('on_message_get, ', cls.__name__,  self._data )
        return self.read()
        

    @classmethod
    def on_message_del(cls, code, *args, **kwargs):
        self = cls.search_by_code(code)
        ret = self.unlink()
        print('on_message_del, ', cls.__name__,  ret, self._data )
        return ret


class Gateway(BaseModel):
    def __init__(self, code):
        super(Gateway, self).__init__(code)

        # Device._records = {
        #     ''
        # }



class Device(BaseModel):
    def __init__(self, code):
        super(Device, self).__init__(code)
        self.set_sensors()
        # self.timeout_count = self.interval


    def set_sensors(self):
        if self._data.get('sensors'):
            return

        sensor_types = ['moisture', 'temperature']

        sensors = [ {
            'code':  'sensor' + self._data['code'][6:] + '.' + str(index),
            'name':  'sensor' + self._data['code'][6:] + '.' + str(index),
            'depth': random.randint(200, 600),
            'sensor_type': sensor_types[ random.randint(0, 1) ]

        } for index in range(0, random.randint(2, 8)) ]

        self._data['sensors'] = sensors

    @property
    def code(self):
        return self._data.get('code')

    @property
    def interval(self):
        return self._data.get('interval', 10)

    @property
    def sensors(self):
        return self._data.get('sensors', [])


    @property
    def timeout_count(self):
        tmr = self._data.get('timeout_count', None )
        if tmr == None:
            self._data[ 'timeout_count' ] = self.interval

        return self._data[ 'timeout_count' ]

    @timeout_count.setter
    def timeout_count(self, count):
        self._data[ 'timeout_count' ] = count


    def publish_put(self, proxy):
        values = {
            'sensors': [ {
                'code': ss['code'], 
                'value': random.randint(1, 30),
                'time': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            } for ss in self.sensors]
        }

        userdata = {
            'function': 'values'
        }

        proxy.publish('put', 'node', self.code, userdata=userdata, values=values)

    @classmethod
    def run_publish(cls, proxy):
        # print('run_publish', )

        for code in cls._records.keys():
            self = cls.search_by_code(code)
            print('run_publish', self.code, self.timeout_count)

            if self.timeout_count > 0:
                self.timeout_count = self.timeout_count - 1
                continue
            else:
                self.timeout_count = self.interval
                self.publish_put(proxy)



            
    # def publish(self, *args, **kwargs):
    #     print('publish', args, kwargs)
    #     topic = '/'.join(['up', self.uuid ] + list(args))
    #     self.controller.push_task( 'publish', topic, kwargs)


    #     pass





env = {
            'router': Gateway, 
            'node': Device
}


def main(uuid, mqtt_host):
    proxy = MqttRouterProxy(uuid, mqtt_host)

    time.sleep(20)

    proxy = MqttRouterProxy(uuid, mqtt_host)

    while(1):
        # kb = input()

        time.sleep(1)

        env['node'].run_publish(proxy)
        






# menu = """
# menu:
# 1. regiter
# 2. publish
# 0. quit
# """

class BAK(object):
    pass
    # def print_menu(self):

    #     print('\n')
    #     print('time', time.strftime('%Y-%m-%d %H:%M:%S') )
    #     print('_data:', self._data)
    #     print(menu)
    #     print('please choice:')



    # def process_message(self, method, func, *args, **kwargs):
    #     if method == 'get' and func == 'config':
    #         self.get_config()

    #     if method == 'put' and func == 'config':
    #         self.put_config(**kwargs)

    #     if method == 'ackput' and func == 'register':
    #         self.ackput_register(**kwargs)


    # def process_keyboard(self, ch):
    #     fns = {
    #         '1': self.menu_regiter,
    #         '2': self.menu_measure,
    #         # '0': lambda: 0
    #     }

    #     if ch == '0':
    #         return 0

    #     fn = fns.get(ch)
    #     if fn:
    #         fn()

    #     return True


    # def run(self):
    #     loop = 1
    #     while(loop):
    #         self.print_menu()
    #         # kb = input('please choice:')
    #         kb = input()
    #         loop = self.process_keyboard(kb)


# if __name__ == '__main__':
#     gateway_id = input('yuor ID (1,2,3,4, ...,):')
#     gateway_id = 'gateway'+gateway_id
#     gateway = Gateway(gateway_id)
#     gateway.run()


